/*
 * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.arialyy.aria.m3u8;

import android.net.TrafficStats;
import android.net.Uri;
import android.os.Process;
import android.text.TextUtils;
import com.arialyy.aria.core.AriaConfig;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.M3U8Entity;
import com.arialyy.aria.core.loader.IInfoTask;
import com.arialyy.aria.core.loader.ILoaderVisitor;
import com.arialyy.aria.core.processor.IBandWidthUrlConverter;
import com.arialyy.aria.core.processor.IKeyUrlConverter;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.wrapper.ITaskWrapper;
import com.arialyy.aria.exception.AriaM3U8Exception;
import com.arialyy.aria.http.ConnectionHelp;
import com.arialyy.aria.http.HttpTaskOption;
import com.arialyy.aria.m3u8.merge.HttpUtils;
import com.arialyy.aria.m3u8.merge.LogUtils;
import com.arialyy.aria.m3u8.merge.M3U8;
import com.arialyy.aria.m3u8.merge.M3U8Constants;
import com.arialyy.aria.m3u8.merge.M3U8Seg;
import com.arialyy.aria.m3u8.merge.M3U8Utils;
import com.arialyy.aria.m3u8.merge.NewM3U8Utils;
import com.arialyy.aria.m3u8.merge.VideoDownloadUtils;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.FileUtil;
import com.arialyy.aria.util.Regular;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
/**
 * 解析url中获取到到m3u8文件信息
 * 协议地址：https://tools.ietf.org/html/rfc8216
 * https://www.cnblogs.com/renhui/p/10351870.html
 * https://blog.csdn.net/Guofengpu/article/details/54922865
 */
final public class M3U8InfoTask implements IInfoTask {
  public static final String M3U8_INDEX_FORMAT = "%s.index";

  private final String TAG = "Aria::M3U8InfoThread";
  private DownloadEntity mEntity;
  private DTaskWrapper mTaskWrapper;
  private int mConnectTimeOut;
  private OnGetLivePeerCallback onGetPeerCallback;
  private HttpTaskOption mHttpOption;
  private M3U8TaskOption mM3U8Option;
  private Callback mCallback;
  //20230418 add
  private boolean hasInitSegment;
  OkHttpClient.Builder  clientBuilder = null;
  Request.Builder builder = null;
  /**
   * 是否停止获取切片信息，{@code true}停止获取切片信息
   */
  private boolean isStop = false;

  @Override public void accept(ILoaderVisitor visitor) {
    visitor.addComponent(this);
  }

  public interface OnGetLivePeerCallback {
    void onGetPeer(String url, String extInf);
  }

  public M3U8InfoTask(DTaskWrapper taskWrapper) {
    this.mTaskWrapper = taskWrapper;
    mEntity = taskWrapper.getEntity();
    mConnectTimeOut = AriaConfig.getInstance().getDConfig().getConnectTimeOut();
    mHttpOption = (HttpTaskOption) taskWrapper.getTaskOption();
    mM3U8Option = (M3U8TaskOption) taskWrapper.getM3u8Option();
    mEntity.getM3U8Entity().setLive(mTaskWrapper.getRequestType() == AbsTaskWrapper.M3U8_LIVE);
  }

  @Override public void run() {
    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    TrafficStats.setThreadStatsTag(UUID.randomUUID().toString().hashCode());

    try {
      String remoteFilePath = String.format(NewM3U8Utils.M3U8_REMOTE_FILE, mEntity.getFilePath());
      M3U8 m3u8 = NewM3U8Utils.parseNetworkM3U8Info(mEntity.getUrl(), remoteFilePath, null, 0);
      if (m3u8 == null) {
        failDownload("m3u8 == null", false);
      } else {
        ALog.d(TAG, "M3U8InfoTask:: TotalsTS = " + m3u8.getTotalsTS());
        if (AriaManager.getInstance().getAppConfig() != null && AriaManager.getInstance().getAriaConfig().getTsMergeMode() == 1) {
          CompleteInfo info = new CompleteInfo();
          info.obj = m3u8;
          onSucceed(info);
        } else {
          Response response = null;
          try {
            URL url = ConnectionHelp.handleUrl(mEntity.getUrl(), mHttpOption);
            clientBuilder = ConnectionHelp.handleConnectionClient( mHttpOption);
            builder = new Request.Builder();
            builder.url(url);
            builder= ConnectionHelp.setConnectParamRequest(mHttpOption, builder);
            builder.addHeader("Range", "bytes=" + 0 + "-");
            clientBuilder.connectTimeout(mConnectTimeOut, TimeUnit.MILLISECONDS);
            response = clientBuilder.build().newCall(builder.build()).execute();
            handleConnect(mEntity.getUrl(),response);
          } catch (IOException e) {
            failDownload(e.getMessage(), false);
          } finally {
            if (response != null) {
              response.close();
            }
          }

        }
      }
    } catch (Exception e) {
      e.printStackTrace();
      failDownload(e.getMessage(), false);
    }

  }



  @Override public void setCallback(Callback callback) {
    mCallback = callback;
  }

  @Override public void stop() {
    this.isStop = true;
  }

  @Override public void cancel() {
    this.isStop = true;
  }

  private void handleConnect(String tsListUrl, Response conn) throws IOException {
    int code = conn.code();
    if (conn.isSuccessful()) {
      BufferedReader reader = new BufferedReader(new InputStreamReader(ConnectionHelp.convertInputStream(conn)));
      String line = reader.readLine();

      if (TextUtils.isEmpty(line) || !line.equalsIgnoreCase("#EXTM3U")) {
        failDownload("读取M3U8信息失败，读取不到#EXTM3U标签", false);
        return;
      }
      List<String> extInf = new ArrayList<>();
      boolean isLive = mTaskWrapper.getRequestType() == ITaskWrapper.M3U8_LIVE;
      boolean isGenerateIndexFile =
          ((M3U8TaskOption) mTaskWrapper.getM3u8Option()).isGenerateIndexFile();
      // 写入索引信息的流
      FileOutputStream fos = null;
      if (isGenerateIndexFile) {
        String indexPath = String.format(M3U8_INDEX_FORMAT, mEntity.getFilePath());
        File indexFile = new File(indexPath);
        if (!indexFile.exists()) {
//          FileUtil.createFile(indexPath);
        } else {
          FileUtil.deleteFile(indexPath);
        }
        fos = new FileOutputStream(indexFile);
//        ALog.d(TAG, line);
        addIndexInfo(true, fos, line);
      }
      int mapIndex = 0;
      while ((line = reader.readLine()) != null) {
        if (isStop) {
          break;
        }
//        ALog.d(TAG, line);
        if (line.startsWith("#EXT-X-ENDLIST")) {
          // 点播文件的下载写入结束标志，直播文件的下载在停止时才写入结束标志
          addIndexInfo(isGenerateIndexFile && !isLive, fos, line);
          break;
        }
        //20230419 add EXT-X-MAP
        if (line.startsWith("#EXT-X-MAP")) {
          String tempInitSegmentUri = M3U8Utils.parseStringAttr(line, M3U8Constants.REGEX_URI);
          if (!TextUtils.isEmpty(tempInitSegmentUri)) {
            hasInitSegment = true;
//            String initSegmentUri = M3U8Utils.getM3U8AbsoluteUrl(videoUrl, tempInitSegmentUri);
//            String segmentByteRange = M3U8Utils.parseOptionalStringAttr(line, M3U8Constants.REGEX_ATTR_BYTERANGE);
//            extInf.add(tempInitSegmentUri);
            getMAPInfo(tsListUrl,tempInitSegmentUri,mapIndex);
            mapIndex ++;
            continue;
          }
        }
        if (line.startsWith("#EXTINF")) {
          //处理
          String url = reader.readLine();
          boolean needCheckUrlRepeat = false;
          if (url.startsWith(M3U8Constants.TAG_BYTERANGE)) {
              needCheckUrlRepeat = true;
              addIndexInfo(isGenerateIndexFile && !isLive, fos, url);
          }
          while (url.startsWith("#EXT")) {
            if (url.startsWith(M3U8Constants.TAG_BYTERANGE)) {
              addIndexInfo(isGenerateIndexFile && !isLive, fos, url);
              needCheckUrlRepeat = true;
            }
            url = reader.readLine();
          }
          if (isLive) {
            if (onGetPeerCallback != null) {
              onGetPeerCallback.onGetPeer(url, line);
            }
          } else {
            if (needCheckUrlRepeat && extInf.contains(url)) {
//              extInf.add(url);
            }else {
              extInf.add(url);
            }
          }
//          ALog.d(TAG, url);
          addIndexInfo(isGenerateIndexFile && !isLive, fos, line);
          addIndexInfo(isGenerateIndexFile && !isLive, fos, url);
          continue;
        }

        if (line.startsWith("#EXT-X-STREAM-INF")) {
          addIndexInfo(isGenerateIndexFile, fos, line);
          int setBand = mM3U8Option.getBandWidth();
          int bandWidth = getBandWidth(line);
          // 多码率的m3u8配置文件，清空信息
          //if (isGenerateIndexFile && mInfos != null) {
          //  mInfos.clear();
          //}
          if (setBand == 0) {
            handleBandWidth(conn, reader.readLine());
          } else if (bandWidth == setBand) {
            handleBandWidth(conn, reader.readLine());
          } else {
            failDownload(String.format("【%s】码率不存在", setBand), false);
          }
          return;
        }

        if (line.startsWith("#EXT-X-KEY")) {
          addIndexInfo(isGenerateIndexFile, fos, line);
          getKeyInfo(tsListUrl, line);
          continue;
        }
        addIndexInfo(isGenerateIndexFile, fos, line);
      }

      if (!isLive && extInf.isEmpty()) {
        failDownload(String.format("获取M3U8下载地址列表失败，url: %s", mEntity.getUrl()), false);
        return;
      }
      if (!isLive && mEntity.getM3U8Entity().getPeerNum() == 0) {
        mEntity.getM3U8Entity().setPeerNum(extInf.size());
        mEntity.getM3U8Entity().update();
      }
      CompleteInfo info = new CompleteInfo();
      info.obj = extInf;
//      if (isGenerateIndexFile) {
//        String indexPath = String.format(M3U8_INDEX_FORMAT, mEntity.getFilePath());
//        BufferedReader fileReader = new BufferedReader(new InputStreamReader(new FileInputStream(indexPath), "UTF-8"));
//        onSucceedConnection(fileReader);
//      }
      onSucceed(info);
      if (fos != null) {
        fos.close();
      }
    } else if (code == HttpURLConnection.HTTP_MOVED_TEMP
        || code == HttpURLConnection.HTTP_MOVED_PERM
        || code == HttpURLConnection.HTTP_SEE_OTHER
        || code == HttpURLConnection.HTTP_CREATED // 201 跳转
        || code == 307) {
      handleUrlReTurn(conn, conn.header("Location"));
    } else if (code >= HttpURLConnection.HTTP_BAD_REQUEST) {
      failDownload("下载失败错误，错误码：" + code, false);
    } else {
      failDownload(String.format("不支持的响应，code: %s", code), true);
    }
  }

  private void onSucceed(CompleteInfo info) {
    if (isStop) {
      return;
    }
    mCallback.onSucceed(mEntity.getKey(), info);
  }
//  private void onSucceedConnection(BufferedReader reader) {
//    if (isStop) {
//      return;
//    }
//    mCallback.onSuccessConnection(mEntity.getKey(),reader);
//  }

  /**
   * 添加切片信息到索引文件中
   * 直播下载的索引只记录头部信息，不记录EXTINF中的信息，该信息在onGetPeer的方法中添加。
   * 点播下载记录所有信息
   *
   * @param write true 将信息写入文件
   * @param info 切片信息
   */
  private void addIndexInfo(boolean write, FileOutputStream fos, String info)
      throws IOException {
    if (!write) {
      return;
    }
    fos.write(info.concat("\r\n").getBytes(Charset.forName("UTF-8")));
  }

  /**
   * 是否停止获取切片信息，{@code true}停止获取切片信息
   */
  public void setStop(boolean isStop) {
    this.isStop = isStop;
  }

  /**
   * 直播切片信息获取回调
   */
  public void setOnGetPeerCallback(OnGetLivePeerCallback peerCallback) {
    onGetPeerCallback = peerCallback;
  }

  /**
   * 获取加密的密钥信息
   */
  private void getKeyInfo(String tsListUrl, String line) {
    String temp = line.substring(line.indexOf(":") + 1);
    // String[] params = temp.split(",");
//    M3U8Entity m3U8Entity = mEntity.getM3U8Entity();
    M3U8Entity m3U8Entity = handleKeyLine(tsListUrl,line);
//    int i = 0;
//    for (String param : params) {
//      if (param.startsWith("METHOD")) {
//        m3U8Entity.method = param.split("=")[1];
//      } else if (param.startsWith("URI")) {
////        m3U8Entity.keyUrl = param.split("=")[1].replaceAll("\"", "");
//        String keyPath;
//        m3U8Entity.keyUrl = M3U8Utils.parseStringAttr(line, M3U8Constants.REGEX_URI);
//        if (((M3U8TaskOption) mTaskWrapper.getM3u8Option()).getKeyPath() == null) {
////          keyPath = new File(mEntity.getFilePath()).getParent() + "/"
////              + CommonUtil.getStrMd5(m3U8Entity.keyUrl) + ".key";
//          keyPath = m3U8Entity.getCacheDir() + "/local_"
//                  + i + ".key";
//          ++i;
//        } else {
//          keyPath = ((M3U8TaskOption) mTaskWrapper.getM3u8Option()).getKeyPath();
//        }
//        m3U8Entity.keyPath = keyPath;
//      } else if (param.startsWith("IV")) {
//        m3U8Entity.iv = param.split("=")[1];
//      } else if (param.startsWith("KEYFORMAT")) {
//        m3U8Entity.keyFormat = param.split("=")[1];
//      } else if (param.startsWith("KEYFORMATVERSIONS")) {
//        m3U8Entity.keyFormatVersion = param.split("=")[1];
//      }
//    }
    downloadKey(tsListUrl, m3U8Entity);
  }
  private  M3U8Entity  handleKeyLine(String tsListUrl, String line) {
    M3U8Entity m3U8Entity = mEntity.getM3U8Entity();
    String method;
    String encryptionIV;
    String encryptionKeyUri;
    method = M3U8Utils.parseOptionalStringAttr(line, M3U8Constants.REGEX_METHOD);
    m3U8Entity.method = method;
    String keyFormat = M3U8Utils.parseOptionalStringAttr(line, M3U8Constants.REGEX_KEYFORMAT);
    m3U8Entity.keyFormat = keyFormat;
    if (!M3U8Constants.METHOD_NONE.equals(method)) {
      encryptionIV = M3U8Utils.parseOptionalStringAttr(line, M3U8Constants.REGEX_IV);
      m3U8Entity.iv = encryptionIV;
      if (M3U8Constants.KEYFORMAT_IDENTITY.equals(keyFormat) || keyFormat == null) {
        if (M3U8Constants.METHOD_AES_128.equals(method)) {
          // The segment is fully encrypted using an identity key.
          String tempKeyUri = M3U8Utils.parseStringAttr(line, M3U8Constants.REGEX_URI);
          m3U8Entity.keyUrl = tempKeyUri;
          if (((M3U8TaskOption) mTaskWrapper.getM3u8Option()).getKeyPath() == null) {
//          keyPath = new File(mEntity.getFilePath()).getParent() + "/"
//              + CommonUtil.getStrMd5(m3U8Entity.keyUrl) + ".key";
            m3U8Entity.keyPath = m3U8Entity.getCacheDir() + "/local_0.key";
          }
//          if (tempKeyUri != null) {
//            encryptionKeyUri = M3U8Utils.getM3U8AbsoluteUrl(tsListUrl, tempKeyUri);
//          }
        } else {
          // Do nothing. Samples are encrypted using an identity key,
          // but this is not supported. Hopefully, a traditional DRM
          // alternative is also provided.
        }
      } else {
        // Do nothing.
      }
    }
    return m3U8Entity;
  }
  //20230419 添加HLS MAP 处理
  /**
   *  获取MAP中的头文件
   */
  private void getMAPInfo(String tsListUrl,String mapUrl,int index) {
    M3U8Entity m3U8Entity = mEntity.getM3U8Entity();
    m3U8Entity.mapUrl = mapUrl;
    m3U8Entity.mapPath = m3U8Entity.getCacheDir() + "/local_" + index + ".map";
    downloadMap(tsListUrl, m3U8Entity);
  }

  /**
   * 读取bandwidth
   */
  private int getBandWidth(String line) {
    Pattern p = Pattern.compile(Regular.BANDWIDTH);
    Matcher m = p.matcher(line);
    if (m.find()) {
      return Integer.parseInt(m.group());
    }
    return 0;
  }

  /**
   * 处理30x跳转
   */
  private void handleUrlReTurn(Response conn, String newUrl) throws IOException {
    ALog.d(TAG, "30x跳转，新url为【" + newUrl + "】");
    if (TextUtils.isEmpty(newUrl) || newUrl.equalsIgnoreCase("null")) {
      if (mCallback != null) {
        mCallback.onFail(mEntity, new AriaM3U8Exception("获取重定向链接失败"), false);
      }
      return;
    }
    String host = "";
    String Protocol = "https";
    try {
      URL url1 = new URL(mEntity.getUrl());
      host = url1.getHost();
      Protocol = url1.getProtocol();

    } catch (MalformedURLException e) {
      ALog.w(TAG, "parser url error");
    }

    if (newUrl.startsWith("//")) {
      newUrl = Protocol + ":" + newUrl;
    }
    //此处存在Bug，有地址是 返回 // 开头的，因此在判断这个条件之前需要先判断// 的情况，并且只要添加 https 协议头即可
    if (newUrl.startsWith("/")) {
      Uri uri = Uri.parse(mEntity.getUrl());
      newUrl = host + newUrl;
    }

    if (!CheckUtil.checkUrl(newUrl)) {
      failDownload("下载失败，重定向url错误", false);
      return;
    }
    mHttpOption.setRedirectUrl(newUrl);
    mEntity.setRedirect(true);
    mEntity.setRedirectUrl(newUrl);
    String cookies = conn.header("Set-Cookie");
    conn.close(); // 关闭上一个连接
    Response response = null;
    try {
      URL url = ConnectionHelp.handleUrl(newUrl, mHttpOption);
      clientBuilder = ConnectionHelp.handleConnectionClient( mHttpOption);
      builder = new Request.Builder();
      builder.url(url);
      builder= ConnectionHelp.setConnectParamRequest(mHttpOption, builder);
      if (!TextUtils.isEmpty(cookies)) {
        builder.addHeader("Cookie", cookies);
      }
      clientBuilder.connectTimeout(mConnectTimeOut, TimeUnit.MILLISECONDS);
      response = clientBuilder.build().newCall(builder.build()).execute();
      handleConnect(mEntity.getUrl(),response);
    } catch (IOException e) {
      failDownload(e.getMessage(), false);
    } finally {
      if (response != null) {
        response.close();
      }
    }
  }

  /**
   * 处理码率
   */
  private void handleBandWidth(Response conn, String bandWidthM3u8Url) throws IOException {
    OkHttpClient.Builder  okHttpClientBuilder = null;
    Request.Builder requestBuilder = null;
    IBandWidthUrlConverter converter = mM3U8Option.isUseDefConvert() ? new BandWidthDefConverter()
        : mM3U8Option.getBandWidthUrlConverter();
    if (converter != null) {
      bandWidthM3u8Url = converter.convert(mEntity.getUrl(), bandWidthM3u8Url);
      if (!bandWidthM3u8Url.startsWith("http")) {
        failDownload(String.format("码率转换器转换后的url地址无效，转换后的url：%s", bandWidthM3u8Url), false);
        return;
      }
    } else {
      ALog.d(TAG, "没有设置码率转换器");
    }
    mM3U8Option.setBandWidthUrl(bandWidthM3u8Url);
    ALog.d(TAG, String.format("新码率url：%s", bandWidthM3u8Url));
    String cookies = conn.header("Set-Cookie");
    conn.close();    // 关闭上一个连接
    Response response = null;
    try {
      URL url = ConnectionHelp.handleUrl(bandWidthM3u8Url, mHttpOption);
      okHttpClientBuilder = ConnectionHelp.handleConnectionClient( mHttpOption);
      requestBuilder = new Request.Builder();
      requestBuilder.url(url);
      requestBuilder= ConnectionHelp.setConnectParamRequest(mHttpOption, requestBuilder);
      if (!TextUtils.isEmpty(cookies)) {
        requestBuilder.addHeader("Cookie", cookies);
      }
      okHttpClientBuilder.connectTimeout(mConnectTimeOut, TimeUnit.MILLISECONDS);
      response = okHttpClientBuilder.build().newCall(requestBuilder.build()).execute();
      handleConnect(mEntity.getUrl(),response);
    } catch (IOException e) {
      failDownload(e.getMessage(), false);
    } finally {
      if (response != null) {
        response.close();
      }
    }
  }

  private void failDownload(String errorInfo, boolean needRetry) {
    if (isStop) {
      return;
    }
//    if (errorInfo != null && errorInfo.contains("open failed: EACCES (Permission denied)")) {
//      String[] arr = errorInfo.split(":");
//      if (arr != null && arr.length > 0) {
//        String filePath = arr[0];
//        if (!TextUtils.isEmpty(filePath) && new File(filePath).exists()) {
//          new File(filePath).delete();
//          needRetry = true;
//        }
//      }
//    }
    mCallback.onFail(mEntity, new AriaM3U8Exception(errorInfo), needRetry);
  }

  /**
   * 密钥不存在，下载密钥
   */
  private void downloadKey(String tsListUr, M3U8Entity info) {
    OkHttpClient.Builder  keyClientBuilder = null;
    Request.Builder keyRequestbuilder = null;
    Response response = null;
    FileOutputStream fos = null;
    try {
      File keyF = new File(info.keyPath);
      if (!keyF.exists()) {
        ALog.d(TAG, "密钥不存在，下载密钥");
        FileUtil.createFile(keyF);
      } else {
        return;
      }

      IKeyUrlConverter keyUrlConverter = mM3U8Option.getKeyUrlConverter();
      String keyUrl = info.keyUrl;
      if (keyUrlConverter != null) {
        keyUrl = keyUrlConverter.convert(mEntity.getUrl(), tsListUr, keyUrl);
      }
      if (TextUtils.isEmpty(keyUrl)) {
        ALog.e(TAG, "m3u8密钥key url 为空");
        return;
      }
      URL url = ConnectionHelp.handleUrl(keyUrl, mHttpOption);
      keyClientBuilder = ConnectionHelp.handleConnectionClient( mHttpOption);
      keyRequestbuilder = new Request.Builder();
      keyRequestbuilder.url(url);
      keyRequestbuilder= ConnectionHelp.setConnectParamRequest(mHttpOption, keyRequestbuilder);
      keyClientBuilder.connectTimeout(mConnectTimeOut, TimeUnit.MILLISECONDS);
      response = keyClientBuilder.build().newCall(keyRequestbuilder.build()).execute();
      handleConnect(mEntity.getUrl(),response);
      InputStream is = ConnectionHelp.convertInputStream(response);
      fos = new FileOutputStream(keyF);
      byte[] buffer = new byte[1024];
      int len;
      while ((len = is.read(buffer)) != -1) {
        fos.write(buffer, 0, len);
      }
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      try {
        if (fos != null) {
          fos.close();
        }
        if (response != null) {
          response.close();
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
  /**
   * MAP头不存在，下载MAP头
   */
  private void downloadMap(String tsListUr, M3U8Entity info) {
    OkHttpClient.Builder  mapClientBuilder = null;
    Request.Builder mapRequestbuilder = null;
    Response response = null;
    FileOutputStream fos = null;
    try {
      File keyF = new File(info.mapPath);
      if (!keyF.exists() || keyF.length() == 0) {
        ALog.d(TAG, "MAP不存在，下载MAP");
        FileUtil.createFile(keyF);
      } else {
        return;
      }
      String mapUrl = M3U8Utils.getM3U8AbsoluteUrl(tsListUr,info.mapUrl);
      if (TextUtils.isEmpty(mapUrl)) {
        ALog.e(TAG, "m3u8MAP url 为空");
        return;
      }
      URL url = ConnectionHelp.handleUrl(mapUrl, mHttpOption);
      mapClientBuilder = ConnectionHelp.handleConnectionClient( mHttpOption);
      mapRequestbuilder = new Request.Builder();
      mapRequestbuilder.url(url);
      mapRequestbuilder= ConnectionHelp.setConnectParamRequest(mHttpOption, mapRequestbuilder);
      mapClientBuilder.connectTimeout(mConnectTimeOut, TimeUnit.MILLISECONDS);
      response = mapClientBuilder.build().newCall(mapRequestbuilder.build()).execute();
      handleConnect(mEntity.getUrl(),response);
      InputStream is = ConnectionHelp.convertInputStream(response);
      int contentLength = (int) response.body().contentLength();
      fos = new FileOutputStream(keyF);

      byte[] buffer = new byte[contentLength];
      int len;
      while ((len = is.read(buffer)) != -1) {
        fos.write(buffer, 0, len);
      }
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      try {
        if (fos != null) {
          fos.close();
        }
        if (response != null) {
          response.close();
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
}
